%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Archivo: simulate.m
% Funcion que realiza la simulacion del sistema en funcion de la probabilidad
% p de que la caja C3 este operativa.  Retorna el tiempo medio de un cliente
% en el sistema y la proporcion de clientes que estuvieron demorados mas 
% de 5 minutos en la cola de OFT.  El parametro max_time es el tiempo durante
% el cual se pueden generar arribos al sistema.

function [mean_time OFT_prop] = simulate(p, max_time)

% Constantes
BUSY = 1;
IDLE = 0;
MAX_INT =  1.0e+030;
FORM = 11;
E1_TYPE1 = E2_TYPE1 = 1;
E1_TYPE2 = E2_TYPE2 = 2;

time = 0.0;             % Reloj de la simulacion
num_clients = 0;        % Cantidad de clientes que se fueron del sistema
ss = ones(1, 9) * IDLE; % Estado de los servidores [R E1 E2 E3 OFT PSF C1 C2 C3]
ql = zeros(1, 7);       % Longitud de las colas [R E1 E2 E3 OFT PSF Cs]
dt = zeros(1, 9);       % Demora acumulada en cada servidor
num_events = 11;        % Numero de eventos

% [Ra Rd E1d E3d OFTd PSFd E2d C1d C2d C3d Fc]
tne = ones(1, 11) * MAX_INT;    % Lista de eventos
tne(1) = time + times2(1);       % Primer arribo

taq{1:7} = zeros(0);    % Tiempos de llegada a cada cola por cliente
form_time = zeros(0);   % Schedule de completado de formularios por cliente

q2_client_type = zeros(0);      % Tipos de clientes en la cola E1
q3_client_type = zeros(0);      % Tipos de clientes en la cola E2

OFT_cc = 0;
OFT_dcc = 0;


%AGREGADO
i=1;
qlPosta = [];%zeros(300,7);
timePosta = [];





while ( time < max_time || norm(ql) > 0 || norm(ss) > 0)

	% Determina el tipo del proximo evento a ocurrir y actualiza el reloj
	[time next_event_type] = min(tne);
	
	if ( next_event_type == 0 )
		error('Lista de eventos vacia');
	end

	switch (next_event_type)   % Invoca al evento apropiado
	case 1 % Arribo a R
		[tne(2) ql(1) taq{1} ss(1) dt(1)] = arrival(time, \
			ss(1), ql(1), taq{1}, dt(1), tne(2), 2);
		if (time <= max_time)  % Programa prox arribo
			tne(1) = time + times2(1);
		else
			tne(1) = MAX_INT;
		end

	case 2 % Salida de R
		[ss(1) tne(2) ql(1) dt(1) taq{1}] = \
		departure(ql(1), ss(1), tne(2), dt(1), taq{1}, 2);
		if (which_way(1) == 0)	
			num_clients++;  % El cliente se va del sistema
		else
			[tne(3) ql(2) taq{2} ss(2) dt(2)] = \    % Pasa a E1
			arrival(time, ss(2), ql(2), taq{2}, dt(2), tne(3), 3);
			q2_client_type(ql(2) + 1) = E1_TYPE1;
		end
	case 3	% Salida de E1 y salida del sistema o llegada a E3
		if (q2_client_type(1) == E1_TYPE1) % Vino de R
			ql(4)++;                % Encolar
			% Programar cuando el cliente termina el formulario
			form_time(ql(4)) = time+times2(FORM);
			taq{4}(ql(4)) = time;   % Guardar tiempo de arribo
			if ( ss(4) == IDLE )
				% Si el este cliente termina el formulario 
				% antes que el primero en la cola
				if (ql(4) > 1 && form_time(ql(4)) < form_time(1))
					shift(taq{4}, 1);
					shift(form_time, 1);
				end
				tne(11) = form_time(1);   % Programar prox evento
			end
		else % Vino de examen reprobado
			num_clients++;   % Se va del sistema
		end
		q2_client_type = shiftl(q2_client_type); % Sacarlo de la cola
		[ss(2) tne(3) ql(2) dt(2) taq{2}] = \          % Salida de E1
		departure(ql(2), ss(2), tne(3), dt(2), taq{2}, 3);
	case 11	% El primer cliente termino de completar el formulario
		ss(4) = BUSY;
		service_time = times2(4);        % Programa una partida
		tne(4) = time + service_time;
		delay = time - taq{4}(1);       % Actualiza demora
		dt(4) += delay + service_time;
		taq{4} = shiftl(taq{4});
		form_time = shiftl(form_time);
		tne(11) = MAX_INT;
		ql(4)--;                        % Actualiza colas
	case 4  % Salida de E3 - Arribo a OFT
		if ( ql(4) == 0) 
			ss(4) = IDLE; tne(4) = MAX_INT;
		else	
			% Atender nuevo cliente si ya completo el formulario
			i = 1;
			while (i <= ql(4) && time < form_time(i))
				i++;
			end
			if (i <= ql(4))    % Alguien termino el formulario
				current_time_arrival = taq{4}(i);
				for j = i:ql(4)-1 
					form_time(j) = form_time(j + 1);
					taq{4}(j) = taq{4}(j + 1);
				end
				ql(4)--;
				if (ql(4) == 0)
					form_time = [];
					taq{4} = [];
				else	% Shift a izquierda de form_time y taq
					form_time = form_time(1:ql(4));
					taq{4} = taq{4}(1:ql(4));
				end
				service_time = times2(4);
				tne(4) = time + service_time;
				delay = time - current_time_arrival;
				dt(4) += delay + service_time;
			else		   % Nadie termino el formulario
				next = min(form_time);
				if (next == 0)
					next = MAX_INT;
				end
				tne(11) = next;
				tne(4) = MAX_INT;
			end
		end
		[tne(5) ql(5) taq{5} ss(5) dt(5)] = \   % Pasa a OFT
			arrival( time, ss(5), ql(5), taq{5}, dt(5), tne(5), 5);
	case 5	% Salida de OFT
		if (ql(5) != 0 && time - taq{5}(1) > 5)
			OFT_dcc++;   % Clientes demorados mas de 5 minutos en OFT
		end
		OFT_cc++;             % Total de clientes que pasaron por OFT
		[ss(5) tne(5) ql(5) dt(5) taq{5}] = \
			departure(ql(5), ss(5), tne(5), dt(5), taq{5}, 5);
	        if (which_way(2) == 1)
                	if (which_way(3) == 1)  % Se va a PSF
                	        [tne(6) ql(6) taq{6} ss(6) dt(6)] = \ % Encolar en PSF
       	        	        arrival(time, ss(6), ql(6), taq{6}, dt(6), tne(6), 6);
               		else    % Se va a E2
	                        [tne(7) ql(3) taq{3} ss(3) dt(3)] = \ % Encolar en E2
                       		arrival(time, ss(3), ql(3), taq{3}, dt(3), tne(7), 7);
				q3_client_type(ql(3) + 1) = E2_TYPE1; % Tipificar
                	end
		else	
               		[tne(3) ql(2) taq{2} ss(2) dt(2)] = \ % Encolar en E1
       		       	arrival(time, ss(2), ql(2), taq{2}, dt(2), tne(3), 3);
       			q2_client_type(ql(2)+1) = E1_TYPE2; % Tipificar cliente
		end
	case 6 % salida de PSF
		[ss(6) tne(6) ql(6) dt(6) taq{6}] = departure( \
		ql(6), ss(6), tne(6), dt(6), taq{6}, 6);
		if (which_way(4) == 1)	% Pasa el examen PSF
               	        [tne(7) ql(3) taq{3} ss(3) dt(3)] = \ % Encolar en E2
       	               	arrival(time, ss(3), ql(3), taq{3}, dt(3), tne(7), 7);
			q3_client_type(ql(3) + 1) = E2_TYPE1; % Tipificar
        	else  % No pasa el examen PSF	
                	[tne(3) ql(2) taq{2} ss(2) dt(2)] = \ % Encolar en E1
               		arrival(time, ss(2), ql(2), taq{2}, dt(2), tne(3), 3);
       		        q2_client_type(ql(2)+1) = E1_TYPE2; % Tipificar
        	end
	case 7	% salida de E2
		primero = q3_client_type(1);	
		q3_client_type = shiftl(q3_client_type);  % Sacarlo de la cola
		[ss(3) tne(7) ql(3) dt(3) taq{3}] = departure(ql(3), \
		ss(3), tne(7), dt(3), taq{3}, 7);
		if (primero == E2_TYPE1)	% Viene de examen medico
			% Si ninguna de las cajas esta disponible
			if ( ss(7) == BUSY && ss(8) == BUSY && 
				(ss(9) == BUSY || ! (rand() < p))) 	
				ql(7)++;
				taq{7}(ql(7)) = time;	% Guardar tiempo de arribo
			else
				[x ns] = min(ss(7:9));  % Busco caja disponible
				ns = ns + 6; 
				ss(ns) = BUSY;
				service_time = times2(ns+1);   % Programa partida
				tne(ns+1) = time + service_time;
				dt(7) += service_time;	% Actualiza demora
			end
		else	% Viene de alguna caja
			num_clients++;	% El cliente se va del sistema.
		end
	case 8  % Salida de C1 - Arribo a E2
		[ss(7) tne(8) ql(7) dt(7) taq{7}] = \	% Salida de C1
			departure(ql(7), ss(7), tne(8), dt(7), taq{7}, 8);
		[tne(7) ql(3) taq{3} ss(3) dt(3)] =\	% Arribo a E2
			arrival(time, ss(3), ql(3), taq{3}, dt(3), tne(7), 7);
		q3_client_type(ql(3)+1) = E2_TYPE2;	% Tipificar cliente
	case 9	% Salida de C2
		[ss(8) tne(9) ql(7) dt(7) taq{7}] = \	% Salida de C2
			departure(ql(7), ss(8), tne(9), dt(7), taq{7}, 9);
		[tne(7) ql(3) taq{3} ss(3) dt(3)] =\	% Arribo a E2
			arrival(time, ss(3), ql(3), taq{3}, dt(3), tne(7), 7);
		q3_client_type(ql(3)+1) = E2_TYPE2;	% Tipificar cliente
	case 10 % Salida de C3
		if ( ql(7) == 0 || !(rand() < p))	% C3 no esta disp.
			ss(9) = IDLE; tne(10) = MAX_INT;
		else
			[ss(9) tne(10) ql(7) dt(7) taq{7}] = \ % Salida de C3
			departure(ql(7), ss(9), tne(10), dt(7), taq{7}, 10);
		end
		[tne(7) ql(3) taq{3} ss(3) dt(3)] =\	% Arribo a E2
			arrival(time, ss(3), ql(3), taq{3}, dt(3), tne(7), 7);
		q3_client_type(ql(3)+1) = E2_TYPE2;	% Tipificar cliente
	end


%AGREGADO
	qlPosta=[ql ; qlPosta];
	timePosta=[timePosta time];
	i=i+1;
 
end
mean_time = sum(dt) / num_clients;
OFT_prop = OFT_dcc / OFT_cc;

end
